#include "login.h"
#include "ui_login.h"
#include "gamepanel.h"
#include "communication.h"
#include "aescrypto.h"
#include "gamemodel.h"
#include <DataManager.h>
#include <QMessageBox>
#include <QRegularExpression>
#include <QRegularExpressionValidator>
#include <QThreadPool>
#include <QCryptographicHash>
#include <QJsonDocument>
#include <QJsonObject>
#include <QFile>

Login::Login(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::Login)
{
    ui->setupUi(this);

    ui->stackedWidget->setCurrentIndex(0);

    setFixedSize(480, 350);

    // 设置窗口之间的切换
    // 登录窗口
    connect(ui->homeBtn, &QPushButton::clicked, this, [=]() {
        ui->stackedWidget->setCurrentIndex(0);
    });
    // 注册窗口
    connect(ui->regUser, &QPushButton::clicked, this, [=]() {
        ui->stackedWidget->setCurrentIndex(1);
    });
    // 网络设置窗口
    connect(ui->netSetBtn, &QPushButton::clicked, this, [=]() {
        ui->stackedWidget->setCurrentIndex(2);
    });

    // 用正则表达式进行数据校验
    QRegularExpression expreg("^[a-zA-Z0-9_]{3,16}$");
    QRegularExpressionValidator* val1 = new QRegularExpressionValidator(expreg, this);
    ui->userName->setValidator(val1);

    /*
     * 密码校验规则:
     * 1. 至少包含一个大写字母、小写字母、数字和特殊字符
     * 2. 密码长度为4到12个字符
     */
    // ?=.*  断言  \\d匹配0-9的数字
    expreg.setPattern("^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d)(?=.*[!@$%*&?])[A-Za-z\\d！@￥%*&?]{4,20}$");
    QRegularExpressionValidator* val2 = new QRegularExpressionValidator(expreg, this);
    ui->password->setValidator(val2);
    ui->regPassword->setValidator(val2);

    // 手机号检验
    expreg.setPattern("^1[3456789]\\d{9}$");
    QRegularExpressionValidator* val3 = new QRegularExpressionValidator(expreg, this);
    ui->phone->setValidator(val3);

    // IP地址的校验        1位.   2位.     3位.
    expreg.setPattern("^((\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.){3}(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])$");
    QRegularExpressionValidator* val4 = new QRegularExpressionValidator(expreg, this);
    ui->ipAddr->setValidator(val4);

    // 端口的校验        0 |  1 ~ 9999     | 10000 ~ 59999 | 60000~64999 |  65000 ~ 65499 |  65500~65529 | 65530~65535
    expreg.setPattern("^(0|([1-9]\\d{0,3})|([1-5]\\d{4})|(6[0-4]\\d{3})|(65[0-4]\\d{2})|(655[0-2]\\d)|(6553[0-5]))$");
    QRegularExpressionValidator* val5 = new QRegularExpressionValidator(expreg, this);
    ui->port->setValidator(val5);

    // 处理按钮点击事件
    connect(ui->loginBtn, &QPushButton::clicked, this, &Login::onLogin);
    connect(ui->registerBtn, &QPushButton::clicked, this, &Login::onRegister);
    connect(ui->netOkBtn, &QPushButton::clicked, this, &Login::onNetOK);

    // 设置线程池的最大线程数
    QThreadPool::globalInstance()->setMaxThreadCount(QThread::idealThreadCount());

    // Test code
    // ui->userName->setText("hello");
    // ui->password->setText("1Aa*");
    // ui->regUserName->setText("xiao");
    // ui->regPassword->setText("1Aa*");
    // ui->phone->setText("15223747548");

    loadUserInfo();

}

Login::~Login()
{
    delete ui;
}

// 数据校验
bool Login::verifyData(QLineEdit* edit)
{
    if (edit->hasAcceptableInput() == false) { // 校验失败
        edit->setStyleSheet("border: 2px solid red");
        return false;
    } else { // 校验成功
        edit->setStyleSheet("none");
    }
    return true;
}

// 连接服务器
void Login::startConnect(Message *msg)
{
    // 未建立连接
    if (!m_isConnected) {
        // 添加任务到线程池
        Communication* task = new Communication(*msg);
        connect(task, &Communication::connectFailed, this, [=]() {
            QMessageBox::critical(this, "连接服务器", "连接服务器失败......");
            m_isConnected = false;
        });
        connect(task, &Communication::loginOk, this, [=]() {
            // 登录成功之后需要将用户名保存到单例对象里面
            DataManager::getInstance()->setUserName(ui->userName->text().toUtf8());
            // 保存用户名和密码
            saveUserInfo();
            // 显示游戏模式窗口(单机版 / 网络版)
            GameModel* model = new GameModel;
            model->show();
            accept();
        });
        connect(task, &Communication::registerOk, this, [=]() {
            // 注册成功之后切换回登录界面
            ui->stackedWidget->setCurrentIndex(0);
        });
        connect(task, &Communication::failedMsg, this, [=](QByteArray msg) {
            QMessageBox::critical(this, "ERROR......", msg);
        });
        m_isConnected = true; // 改变连接状态
        QThreadPool::globalInstance()->start(task);
        // 添加通信对象
        DataManager::getInstance()->setCommunication(task);
    } else
    // 已建立连接
    {

        // 直接与服务器进行通信
        DataManager::getInstance()->getCommunication()->sendMessage(msg);
    }
}

// 保存用户数据
/*
 *  1. 用AES密钥对Json文件进行加密
 *  2. 将加密的Json文件进行Base64编码
 *  3. 向文件中写入数据
 */
void Login::saveUserInfo()
{
    if (ui->savePwd->isChecked()) {
        QJsonObject obj;
        obj.insert("user", ui->userName->text());
        obj.insert("passwd", ui->password->text());
        QJsonDocument doc(obj);
        QByteArray json = doc.toJson();
        // 对Json文件进行AES加密
        QByteArray key = KEY.left(16);
        if (key.size() != 16) {
            qDebug() << __FILE__  << ":" <<  __FUNCTION__ << ":"  << __LINE__ << ":" << "the AES key is error......";
            assert(key.size() != 16);
        }
        AesCrypto aes(AesCrypto::AES_CBC_128, key);
        json = aes.encrypt(json);
        // 将加密后的数据转换为Base64编码
        QByteArray base64EncryptedJson = json.toBase64();
        // 写文件保存数据
        QFile file("passwd.bin");
        bool flag = file.open(QFile::WriteOnly);
        if (!flag) {
            qDebug() << __FILE__  << ":" <<  __FUNCTION__ << ":"  << __LINE__ << ":" << "failed open file......";
        }
        file.write(base64EncryptedJson);
        file.close();
    } else {
        QFile file("passwd.bin");
        file.remove();
    }
}

// 加载用户数据
/*
 * 1. 从文件中读取Base64编码的Json密文
 * 2. 对Base64编码的Json密文进行解码
 * 3. 使用AES的密钥对Json密文进行解密，得到原始Json数据
 **/
void Login::loadUserInfo()
{
    QFile file("passwd.bin");
    bool flag = file.open(QFile::ReadOnly);
    if (flag) {
        ui->savePwd->setChecked(true);
        // 读取Base64编码的Json密文
        QByteArray base64EncryptedJson = file.readAll();
        file.close();
        // 对Base64编码的Json密文进行解码
        QByteArray encryptedJson = QByteArray::fromBase64(base64EncryptedJson);

        // 使用AES的密钥对Json密文进行解密，得到原始Json数据
        QByteArray key = KEY.left(16);
        if (key.size() != 16) {
            qDebug() << __FILE__  << ":" <<  __FUNCTION__ << ":"  << __LINE__ << ":" << "the AES key is error......";
            assert(key.size() != 16);
        }
        AesCrypto aes(AesCrypto::AES_CBC_128, key);
        QByteArray decryptedjson = aes.decrypt(encryptedJson);

        QJsonDocument doc = QJsonDocument::fromJson(decryptedjson);
        QJsonObject obj = doc.object();
        QString name = obj.value("user").toString();
        QString passwd = obj.value("passwd").toString();
        ui->userName->setText(name);
        ui->password->setText(passwd);
    } else {
        ui->savePwd->setChecked(false);
    }
}

// 保存用户数据
/*
     * 为了保证密码的安全性：
     * 1. 先生成一个随机的salt
     * 2. 将salt与密码进行拼接
     * 3. 将拼接的字符串进行哈希
     * 4. 将数据保存到Json文件(哈希之后的密码与salt用Hex格式编码)
     * 5. 用AES密钥对Json文件进行加密
     * 6. 将加密的Json文件进行Base64编码
     * 7. 向文件中写入数据
     */
/*
void Login::saveUserInfo()
{

    if (ui->savePwd->isChecked()) {
        // 生成一个随机的salt
        QByteArray salt = QCryptographicHash::hash(QDateTime::currentDateTime().toString().toUtf8(), QCryptographicHash::Sha256);
        // 对密码进行哈希处理
        QByteArray hashedPassword = QCryptographicHash::hash(ui->password->text().toUtf8() + salt, QCryptographicHash::Sha256);

        QJsonObject obj;
        obj.insert("user", ui->userName->text());
        obj.insert("passwdHash", hashedPassword.toHex());
        obj.insert("salt", salt.toHex());

        QJsonDocument doc(obj);
        QByteArray json = doc.toJson();
        // 对Json文件进行AES加密
        QByteArray key = KEY.left(16);
        if (key.size() != 16) {
            qDebug() << __FILE__  << ":" <<  __FUNCTION__ << ":"  << __LINE__ << ":" << "the AES key is error......";
            assert(key.size() != 16);
        }
        AesCrypto aes(AesCrypto::AES_CBC_128, key);
        json = aes.encrypt(json);
        // 将加密后的数据转换为Base64编码
        QByteArray base64EncryptedJson = encryptedJson.toBase64();
        // 写文件保存数据
        QFile file("passwd.bin");
        bool flag = file.open(QFile::WriteOnly);
        if (!flag) {
            qDebug() << __FILE__  << ":" <<  __FUNCTION__ << ":"  << __LINE__ << ":" << "failed open file......";
        }
        file.write(base64EncryptedJson);
        file.close();
    } else {
        QFile file("passwd.bin");
        file.remove();
    }
}
*/

// 加载用户数据
/*
     * 为了保证密码的安全性：
     * 1. 从文件中读取Base64编码的Json密文
     * 2. 对Base64编码的Json密文进行解码
     * 3. 使用AES的密钥对Json密文进行解密，得到原始Json数据
     *
     */
/*
void Login::loadUserInfo()
{
    // 如果加载到了用户数据，则勾选记住密码单选框
    QFile file("passwd.bin");
    bool flag = file.open(QFile::ReadOnly);
    if (flag) {
        ui->savePwd->setChecked(true);
        // 读取Base64编码的Json密文
        QByteArray base64EncryptedJson = file.readAll();
        file.close();
        // 对Base64编码的Json密文进行解码
        QByteArray encryptedJson = QByteArray::fromBase64(base64EncryptedJson);

        // 使用AES的密钥对Json密文进行解密，得到原始Json数据
        QByteArray key = KEY.left(16);
        if (key.size() != 16) {
            qDebug() << __FILE__  << ":" <<  __FUNCTION__ << ":"  << __LINE__ << ":" << "the AES key is error......";
            assert(key.size() != 16);
        }
        AesCrypto aes(AesCrypto::AES_CBC_128, key);
        QByteArray decryptedjson = aes.decrypt(encryptedJson);

        QJsonDocument doc = QJsonDocument::fromJson(decryptedjson);
        QJsonObject obj = doc.object();
        QString name = obj.value("user").toString();
        QString passwd = QByteArray::fromHex(obj.value("passwdHash").toString().toUtf8());
        QString salt = QByteArray::fromHex(obj.value("salt").toString().toUtf8());



    } else {
        ui->savePwd->setChecked(false);
    }
}
*/

// 处理登录信号的槽函数
void Login::onLogin()
{
    bool flag1 = verifyData(ui->userName);
    bool flag2 = verifyData(ui->password);
    if (flag1 && flag2) {
        // GamePanel* panel = new GamePanel;
        // panel->show();
        Message msg;
        msg.userName = ui->userName->text().toUtf8();
        msg.reqcode = RequestCode::UserLogin;
        QByteArray passwd = ui->password->text().toUtf8();
        // 将密码进行哈希计算出哈希散列值
        passwd = QCryptographicHash::hash(passwd, QCryptographicHash::Sha224).toHex();
        msg.data1 = passwd;
        // 连接服务器
        startConnect(&msg);
    }
}

// 处理注册信号的槽函数
void Login::onRegister()
{
    bool flag1 = verifyData(ui->regUserName);
    bool flag2 = verifyData(ui->regPassword);
    bool flag3 = verifyData(ui->phone);

    if (flag1 && flag2 && flag3) {
        Message msg;
        msg.userName = ui->regUserName->text().toUtf8();
        msg.reqcode = RequestCode::Register;
        QByteArray passwd = ui->regPassword->text().toUtf8();

        // 将密码进行哈希计算出哈希散列值
        passwd = QCryptographicHash::hash(passwd, QCryptographicHash::Sha224).toHex();

        msg.data1 = passwd;
        msg.data2 = ui->phone->text().toUtf8();

        // 连接服务器
        startConnect(&msg);
    }
}

// 处理网络配置确定信号
void Login::onNetOK()
{
    bool flag1 = verifyData(ui->ipAddr);
    bool flag2 = verifyData(ui->port);
    if (flag1 && flag2) {
        DataManager* instance = DataManager::getInstance();
        instance->setIp(ui->ipAddr->text().toUtf8());
        instance->setPort(ui->port->text().toUtf8());
    }
}
